{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Configurations for Colab"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import sys\n",
    "IN_COLAB = 'google.colab' in sys.modules\n",
    "\n",
    "if IN_COLAB:\n",
    "    !apt-get install -y xvfb python-opengl > /dev/null 2>&1\n",
    "    !pip install gym pyvirtualdisplay > /dev/null 2>&1\n",
    "    !pip install JSAnimation==0.1\n",
    "    \n",
    "    from pyvirtualdisplay import Display\n",
    "    \n",
    "    # Start virtual display\n",
    "    dis = Display(visible=0, size=(400, 400))\n",
    "    dis.start()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 07. N-Step Learning\n",
    "\n",
    "[R. S. Sutton, \"Learning to predict by the methods of temporal differences.\" Machine learning, 3(1):9–44, 1988.](http://incompleteideas.net/papers/sutton-88-with-erratum.pdf)\n",
    "\n",
    "Q-learning accumulates a single reward and then uses the greedy action at the next step to bootstrap. Alternatively, forward-view multi-step targets can be used (Sutton 1988). We call it Truncated N-Step Return\n",
    "from a given state $S_t$. It is defined as,\n",
    "\n",
    "$$\n",
    "R^{(n)}_t = \\sum_{k=0}^{n-1} \\gamma_t^{(k)} R_{t+k+1}.\n",
    "$$\n",
    "\n",
    "A multi-step variant of DQN is then defined by minimizing the alternative loss,\n",
    "\n",
    "$$\n",
    "(R^{(n)}_t + \\gamma^{(n)}_t \\max_{a'} q_{\\theta}^{-}\n",
    "(S_{t+n}, a')\n",
    "− q_{\\theta}(S_t, A_t))^2.\n",
    "$$\n",
    "\n",
    "Multi-step targets with suitably tuned $n$ often lead to faster learning (Sutton and Barto 1998)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "from collections import deque\n",
    "from typing import Deque, Dict, List, Tuple\n",
    "\n",
    "import gym\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.optim as optim\n",
    "from IPython.display import clear_output\n",
    "from torch.nn.utils import clip_grad_norm_"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Replay buffer for N-step learning\n",
    "\n",
    "There are a little bit changes in Replay buffer for N-step learning. First, we use `deque` to store the most recent n-step transitions.\n",
    "\n",
    "```python\n",
    "    self.n_step_buffer = deque(maxlen=n_step)\n",
    "```\n",
    "\n",
    "You can see it doesn't actually store a transition in the buffer, unless `n_step_buffer` is full.\n",
    "\n",
    "```\n",
    "    # in store method\n",
    "    if len(self.n_step_buffer) < self.n_step:\n",
    "        return False\n",
    "```\n",
    "\n",
    "When the length of `n_step_buffer` becomes equal to N, it eventually stores the N-step transition, which is calculated by `_get_n_step_info` method.\n",
    "\n",
    "(Please see *01.dqn.ipynb* for detailed description of the basic replay buffer.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "class ReplayBuffer:\n",
    "    \"\"\"A simple numpy replay buffer.\"\"\"\n",
    "\n",
    "    def __init__(\n",
    "        self, \n",
    "        obs_dim: int, \n",
    "        size: int, \n",
    "        batch_size: int = 32, \n",
    "        n_step: int = 3, \n",
    "        gamma: float = 0.99,\n",
    "    ):\n",
    "        self.obs_buf = np.zeros([size, obs_dim], dtype=np.float32)\n",
    "        self.next_obs_buf = np.zeros([size, obs_dim], dtype=np.float32)\n",
    "        self.acts_buf = np.zeros([size], dtype=np.float32)\n",
    "        self.rews_buf = np.zeros([size], dtype=np.float32)\n",
    "        self.done_buf = np.zeros(size, dtype=np.float32)\n",
    "        self.max_size, self.batch_size = size, batch_size\n",
    "        self.ptr, self.size, = 0, 0\n",
    "        \n",
    "        # for N-step Learning\n",
    "        self.n_step_buffer = deque(maxlen=n_step)\n",
    "        self.n_step = n_step\n",
    "        self.gamma = gamma\n",
    "\n",
    "    def store(\n",
    "        self, \n",
    "        obs: np.ndarray, \n",
    "        act: np.ndarray, \n",
    "        rew: float, \n",
    "        next_obs: np.ndarray, \n",
    "        done: bool\n",
    "    ) -> bool:\n",
    "        transition = (obs, act, rew, next_obs, done)\n",
    "        self.n_step_buffer.append(transition)\n",
    "\n",
    "        # single step transition is not ready\n",
    "        if len(self.n_step_buffer) < self.n_step:\n",
    "            return False\n",
    "        \n",
    "        # make a n-step transition\n",
    "        rew, next_obs, done = self._get_n_step_info(\n",
    "            self.n_step_buffer, self.gamma\n",
    "        )\n",
    "        obs, action = self.n_step_buffer[0][:2]\n",
    "        \n",
    "        self.obs_buf[self.ptr] = obs\n",
    "        self.next_obs_buf[self.ptr] = next_obs\n",
    "        self.acts_buf[self.ptr] = act\n",
    "        self.rews_buf[self.ptr] = rew\n",
    "        self.done_buf[self.ptr] = done\n",
    "        self.ptr = (self.ptr + 1) % self.max_size\n",
    "        self.size = min(self.size + 1, self.max_size)\n",
    "        \n",
    "        return True\n",
    "\n",
    "    def sample_batch(self) -> Dict[str, np.ndarray]:\n",
    "        indices = np.random.choice(\n",
    "            self.size, size=self.batch_size, replace=False\n",
    "        )\n",
    "\n",
    "        return dict(\n",
    "            obs=self.obs_buf[indices],\n",
    "            next_obs=self.next_obs_buf[indices],\n",
    "            acts=self.acts_buf[indices],\n",
    "            rews=self.rews_buf[indices],\n",
    "            done=self.done_buf[indices],\n",
    "            # for N-step Learning\n",
    "            indices=indices,\n",
    "        )\n",
    "    \n",
    "    def sample_batch_from_idxs(\n",
    "        self, indices: np.ndarray\n",
    "    ) -> Dict[str, np.ndarray]:\n",
    "        # for N-step Learning\n",
    "        return dict(\n",
    "            obs=self.obs_buf[indices],\n",
    "            next_obs=self.next_obs_buf[indices],\n",
    "            acts=self.acts_buf[indices],\n",
    "            rews=self.rews_buf[indices],\n",
    "            done=self.done_buf[indices],\n",
    "        )\n",
    "    \n",
    "    def _get_n_step_info(\n",
    "        self, n_step_buffer: Deque, gamma: float\n",
    "    ) -> Tuple[np.int64, np.ndarray, bool]:\n",
    "        \"\"\"Return n step rew, next_obs, and done.\"\"\"\n",
    "        # info of the last transition\n",
    "        rew, next_obs, done = n_step_buffer[-1][-3:]\n",
    "\n",
    "        for transition in reversed(list(n_step_buffer)[:-1]):\n",
    "            r, n_o, d = transition[-3:]\n",
    "\n",
    "            rew = r + gamma * rew * (1 - d)\n",
    "            next_obs, done = (n_o, d) if d else (next_obs, done)\n",
    "\n",
    "        return rew, next_obs, done\n",
    "\n",
    "    def __len__(self) -> int:\n",
    "        return self.size"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Network\n",
    "\n",
    "We are going to use a simple network architecture with three fully connected layers and two non-linearity functions (ReLU)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Network(nn.Module):\n",
    "    def __init__(self, in_dim: int, out_dim: int):\n",
    "        \"\"\"Initialization.\"\"\"\n",
    "        super(Network, self).__init__()\n",
    "\n",
    "        self.layers = nn.Sequential(\n",
    "            nn.Linear(in_dim, 128), \n",
    "            nn.ReLU(),\n",
    "            nn.Linear(128, 128), \n",
    "            nn.ReLU(), \n",
    "            nn.Linear(128, out_dim)\n",
    "        )\n",
    "\n",
    "    def forward(self, x: torch.Tensor) -> torch.Tensor:\n",
    "        \"\"\"Forward method implementation.\"\"\"\n",
    "        return self.layers(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## DQN Agent + N-step learning Agent\n",
    "\n",
    "Here is a summary of DQNAgent class.\n",
    "\n",
    "| Method           | Note                                                 |\n",
    "| ---              | ---                                                  |\n",
    "|select_action     | select an action from the input state.               |\n",
    "|step              | take an action and return the response of the env.   |\n",
    "|compute_dqn_loss  | return dqn loss.                                     |\n",
    "|update_model      | update the model by gradient descent.                |\n",
    "|target_hard_update| hard update from the local model to the target model.|\n",
    "|train             | train the agent during num_frames.                   |\n",
    "|test              | test the agent (1 episode).                          |\n",
    "|plot              | plot the training progresses.                        |\n",
    "\n",
    "We use two buffers: `memory` and `memory_n` for 1-step transitions and n-step transitions respectively. It guarantees that any paired 1-step and n-step transitions have the same indices (See `step` method for more details). Due to the reason, we can sample pairs of transitions from the two buffers once we have indices for samples.\n",
    "\n",
    "```python\n",
    "    def update_model(self) -> torch.Tensor:\n",
    "        ...\n",
    "        samples = self.memory.sample_batch()\n",
    "        indices = samples[\"indices\"]\n",
    "        ...\n",
    "        \n",
    "        # N-step Learning loss\n",
    "        if self.use_n_step:\n",
    "            samples = self.memory_n.sample_batch_from_idxs(indices)\n",
    "            ...\n",
    "```\n",
    "\n",
    "One thing to note that  we are gonna combine 1-step loss and n-step loss so as to control high-variance / high-bias trade-off.\n",
    "\n",
    "(Search the comments with *N-step Leaning* to see any difference from DQN.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "class DQNAgent:\n",
    "    \"\"\"DQN Agent interacting with environment.\n",
    "    \n",
    "    Attribute:\n",
    "        env (gym.Env): openAI Gym environment\n",
    "        memory (ReplayBuffer): replay memory to store transitions\n",
    "        batch_size (int): batch size for sampling\n",
    "        epsilon (float): parameter for epsilon greedy policy\n",
    "        epsilon_decay (float): step size to decrease epsilon\n",
    "        max_epsilon (float): max value of epsilon\n",
    "        min_epsilon (float): min value of epsilon\n",
    "        target_update (int): period for target model's hard update\n",
    "        gamma (float): discount factor\n",
    "        dqn (Network): model to train and select actions\n",
    "        dqn_target (Network): target model to update\n",
    "        optimizer (torch.optim): optimizer for training dqn\n",
    "        transition (list): transition information including \n",
    "                           state, action, reward, next_state, done\n",
    "        use_n_step (bool): whether to use n_step memory\n",
    "        n_step (int): step number to calculate n-step td error\n",
    "        memory_n (ReplayBuffer): n-step replay buffer\n",
    "    \"\"\"\n",
    "\n",
    "    def __init__(\n",
    "        self, \n",
    "        env: gym.Env,\n",
    "        memory_size: int,\n",
    "        batch_size: int,\n",
    "        target_update: int,\n",
    "        epsilon_decay: float,\n",
    "        max_epsilon: float = 1.0,\n",
    "        min_epsilon: float = 0.1,\n",
    "        gamma: float = 0.99,\n",
    "        # N-step Learning\n",
    "        n_step: int = 3,\n",
    "    ):\n",
    "        \"\"\"Initialization.\n",
    "        \n",
    "        Args:\n",
    "            env (gym.Env): openAI Gym environment\n",
    "            memory_size (int): length of memory\n",
    "            batch_size (int): batch size for sampling\n",
    "            target_update (int): period for target model's hard update\n",
    "            epsilon_decay (float): step size to decrease epsilon\n",
    "            lr (float): learning rate\n",
    "            max_epsilon (float): max value of epsilon\n",
    "            min_epsilon (float): min value of epsilon\n",
    "            gamma (float): discount factor\n",
    "            n_step (int): step number to calculate n-step td error\n",
    "        \"\"\"\n",
    "        obs_dim = env.observation_space.shape[0]\n",
    "        action_dim = env.action_space.n\n",
    "        \n",
    "        self.env = env\n",
    "        self.batch_size = batch_size\n",
    "        self.epsilon = max_epsilon\n",
    "        self.epsilon_decay = epsilon_decay\n",
    "        self.max_epsilon = max_epsilon\n",
    "        self.min_epsilon = min_epsilon\n",
    "        self.target_update = target_update\n",
    "        self.gamma = gamma\n",
    "        \n",
    "        # memory for 1-step Learning\n",
    "        self.memory = ReplayBuffer(\n",
    "            obs_dim, memory_size, batch_size, n_step=1\n",
    "        )\n",
    "        \n",
    "        # memory for N-step Learning\n",
    "        self.use_n_step = True if n_step > 1 else False\n",
    "        if self.use_n_step:\n",
    "            self.n_step = n_step\n",
    "            self.memory_n = ReplayBuffer(\n",
    "                obs_dim, memory_size, batch_size, n_step=n_step, gamma=gamma\n",
    "            )\n",
    "        \n",
    "        # device: cpu / gpu\n",
    "        self.device = torch.device(\n",
    "            \"cuda\" if torch.cuda.is_available() else \"cpu\"\n",
    "        )\n",
    "        print(self.device)\n",
    "\n",
    "        # networks: dqn, dqn_target\n",
    "        self.dqn = Network(obs_dim, action_dim).to(self.device)\n",
    "        self.dqn_target = Network(obs_dim, action_dim).to(self.device)\n",
    "        self.dqn_target.load_state_dict(self.dqn.state_dict())\n",
    "        self.dqn_target.eval()\n",
    "        \n",
    "        # optimizer\n",
    "        self.optimizer = optim.Adam(self.dqn.parameters())\n",
    "\n",
    "        # transition to store in memory\n",
    "        self.transition = list()\n",
    "        \n",
    "        # mode: train / test\n",
    "        self.is_test = False\n",
    "\n",
    "    def select_action(self, state: np.ndarray) -> np.ndarray:\n",
    "        \"\"\"Select an action from the input state.\"\"\"\n",
    "        # epsilon greedy policy\n",
    "        if self.epsilon > np.random.random():\n",
    "            selected_action = self.env.action_space.sample()\n",
    "        else:\n",
    "            selected_action = self.dqn(\n",
    "                torch.FloatTensor(state).to(self.device)\n",
    "            ).argmax()\n",
    "            selected_action = selected_action.detach().cpu().numpy()\n",
    "        \n",
    "        if not self.is_test:\n",
    "            self.transition = [state, selected_action]\n",
    "        \n",
    "        return selected_action\n",
    "\n",
    "    def step(self, action: np.ndarray) -> Tuple[np.ndarray, np.float64, bool]:\n",
    "        \"\"\"Take an action and return the response of the env.\"\"\"\n",
    "        next_state, reward, done, _ = self.env.step(action)\n",
    "\n",
    "        if not self.is_test:\n",
    "            self.transition += [reward, next_state, done]\n",
    "            \n",
    "            # add N-step transition\n",
    "            if self.use_n_step:\n",
    "                is_n_step_stored = self.memory_n.store(*self.transition)\n",
    "\n",
    "            # add a single step transition\n",
    "            if not self.use_n_step or is_n_step_stored:\n",
    "                self.memory.store(*self.transition)\n",
    "    \n",
    "        return next_state, reward, done\n",
    "\n",
    "    def update_model(self) -> torch.Tensor:\n",
    "        \"\"\"Update the model by gradient descent.\"\"\"\n",
    "        samples = self.memory.sample_batch()\n",
    "        indices = samples[\"indices\"]\n",
    "        loss = self._compute_dqn_loss(samples, self.gamma)\n",
    "        \n",
    "        # N-step Learning loss\n",
    "        # we are gonna combine 1-step loss and n-step loss so as to\n",
    "        # prevent high-variance.\n",
    "        if self.use_n_step:\n",
    "            samples = self.memory_n.sample_batch_from_idxs(indices)\n",
    "            gamma = self.gamma ** self.n_step\n",
    "            n_loss = self._compute_dqn_loss(samples, gamma)\n",
    "            loss += n_loss\n",
    "\n",
    "        self.optimizer.zero_grad()\n",
    "        loss.backward()\n",
    "        # gradient clipping\n",
    "        # https://pytorch.org/docs/stable/nn.html#torch.nn.utils.clip_grad_norm_\n",
    "        clip_grad_norm_(self.dqn.parameters(), 1.0, norm_type=1)\n",
    "        self.optimizer.step()\n",
    "\n",
    "        return loss.item()\n",
    "        \n",
    "    def train(self, num_frames: int, plotting_interval: int = 200):\n",
    "        \"\"\"Train the agent.\"\"\"\n",
    "        self.is_test = False\n",
    "        \n",
    "        state = self.env.reset()\n",
    "        update_cnt = 0\n",
    "        epsilons = []\n",
    "        losses = []\n",
    "        scores = []\n",
    "        score = 0\n",
    "\n",
    "        for frame_idx in range(1, num_frames + 1):\n",
    "            action = self.select_action(state)\n",
    "            next_state, reward, done = self.step(action)\n",
    "\n",
    "            state = next_state\n",
    "            score += reward\n",
    "\n",
    "            # if episode ends\n",
    "            if done:\n",
    "                state = env.reset()\n",
    "                scores.append(score)\n",
    "                score = 0\n",
    "\n",
    "            # if training is ready\n",
    "            if len(self.memory) >= self.batch_size:\n",
    "                loss = self.update_model()\n",
    "                losses.append(loss)\n",
    "                update_cnt += 1\n",
    "                \n",
    "                # linearly decrease epsilon\n",
    "                self.epsilon = max(\n",
    "                    self.min_epsilon, self.epsilon - (\n",
    "                        self.max_epsilon - self.min_epsilon\n",
    "                    ) * self.epsilon_decay\n",
    "                )\n",
    "                epsilons.append(self.epsilon)\n",
    "                \n",
    "                # if hard update is needed\n",
    "                if update_cnt % self.target_update == 0:\n",
    "                    self._target_hard_update()\n",
    "\n",
    "            # plotting\n",
    "            if frame_idx % plotting_interval == 0:\n",
    "                self._plot(frame_idx, scores, losses, epsilons)\n",
    "                \n",
    "        self.env.close()\n",
    "                \n",
    "    def test(self) -> List[np.ndarray]:\n",
    "        \"\"\"Test the agent.\"\"\"\n",
    "        self.is_test = True\n",
    "        \n",
    "        state = self.env.reset()\n",
    "        done = False\n",
    "        score = 0\n",
    "        \n",
    "        frames = []\n",
    "        while not done:\n",
    "            frames.append(self.env.render(mode=\"rgb_array\"))\n",
    "            action = self.select_action(state)\n",
    "            next_state, reward, done = self.step(action)\n",
    "\n",
    "            state = next_state\n",
    "            score += reward\n",
    "        \n",
    "        print(\"score: \", score)\n",
    "        self.env.close()\n",
    "        \n",
    "        return frames\n",
    "    \n",
    "    def _compute_dqn_loss(\n",
    "        self, \n",
    "        samples: Dict[str, np.ndarray], \n",
    "        gamma: float\n",
    "    ) -> torch.Tensor:\n",
    "        \"\"\"Return dqn loss.\"\"\"\n",
    "        device = self.device  # for shortening the following lines\n",
    "        state = torch.FloatTensor(samples[\"obs\"]).to(device)\n",
    "        next_state = torch.FloatTensor(samples[\"next_obs\"]).to(device)\n",
    "        action = torch.LongTensor(samples[\"acts\"].reshape(-1, 1)).to(device)\n",
    "        reward = torch.FloatTensor(samples[\"rews\"].reshape(-1, 1)).to(device)\n",
    "        done = torch.FloatTensor(samples[\"done\"].reshape(-1, 1)).to(device)\n",
    "\n",
    "        # G_t   = r + gamma * v(s_{t+1})  if state != Terminal\n",
    "        #       = r                       otherwise\n",
    "        curr_q_value = self.dqn(state).gather(1, action)\n",
    "        next_q_value = self.dqn_target(next_state).max(\n",
    "            dim=1, keepdim=True\n",
    "        )[0].detach()\n",
    "        mask = 1 - done\n",
    "        target = (reward + gamma * next_q_value * mask).to(self.device)\n",
    "\n",
    "        # calculate dqn loss\n",
    "        loss = ((target - curr_q_value).pow(2)).mean()\n",
    "\n",
    "        return loss\n",
    "\n",
    "    def _target_hard_update(self):\n",
    "        \"\"\"Hard update: target <- local.\"\"\"\n",
    "        self.dqn_target.load_state_dict(self.dqn.state_dict())\n",
    "                \n",
    "    def _plot(\n",
    "        self, \n",
    "        frame_idx: int, \n",
    "        scores: List[float], \n",
    "        losses: List[float], \n",
    "        epsilons: List[float],\n",
    "    ):\n",
    "        \"\"\"Plot the training progresses.\"\"\"\n",
    "        clear_output(True)\n",
    "        plt.figure(figsize=(20, 5))\n",
    "        plt.subplot(131)\n",
    "        plt.title('frame %s. score: %s' % (frame_idx, np.mean(scores[-10:])))\n",
    "        plt.plot(scores)\n",
    "        plt.subplot(132)\n",
    "        plt.title('loss')\n",
    "        plt.plot(losses)\n",
    "        plt.subplot(133)\n",
    "        plt.title('epsilons')\n",
    "        plt.plot(epsilons)\n",
    "        plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Environment\n",
    "\n",
    "You can see the [code](https://github.com/openai/gym/blob/master/gym/envs/classic_control/cartpole.py) and [configurations](https://github.com/openai/gym/blob/master/gym/envs/__init__.py#L53) of CartPole-v0 from OpenAI's repository."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# environment\n",
    "env_id = \"CartPole-v0\"\n",
    "env = gym.make(env_id)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Set random seed"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[777]"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "seed = 777\n",
    "\n",
    "def seed_torch(seed):\n",
    "    torch.manual_seed(seed)\n",
    "    if torch.backends.cudnn.enabled:\n",
    "        torch.backends.cudnn.benchmark = False\n",
    "        torch.backends.cudnn.deterministic = True\n",
    "\n",
    "np.random.seed(seed)\n",
    "seed_torch(seed)\n",
    "env.seed(seed)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Initialize"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "cuda\n"
     ]
    }
   ],
   "source": [
    "# parameters\n",
    "num_frames = 10000\n",
    "memory_size = 1000\n",
    "batch_size = 32\n",
    "target_update = 200\n",
    "epsilon_decay = 1 / 2000\n",
    "\n",
    "# train\n",
    "agent = DQNAgent(env, memory_size, batch_size, target_update, epsilon_decay)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Train"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 1440x360 with 3 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "agent.train(num_frames)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Test\n",
    "\n",
    "Run the trained agent (1 episode)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "score:  200.0\n"
     ]
    }
   ],
   "source": [
    "frames = agent.test()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Render"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<script language=\"javascript\">\n",
       "  /* Define the Animation class */\n",
       "  function Animation(frames, img_id, slider_id, interval, loop_select_id){\n",
       "    this.img_id = img_id;\n",
       "    this.slider_id = slider_id;\n",
       "    this.loop_select_id = loop_select_id;\n",
       "    this.interval = interval;\n",
       "    this.current_frame = 0;\n",
       "    this.direction = 0;\n",
       "    this.timer = null;\n",
       "    this.frames = new Array(frames.length);\n",
       "\n",
       "    for (var i=0; i<frames.length; i++)\n",
       "    {\n",
       "     this.frames[i] = new Image();\n",
       "     this.frames[i].src = frames[i];\n",
       "    }\n",
       "    document.getElementById(this.slider_id).max = this.frames.length - 1;\n",
       "    this.set_frame(this.current_frame);\n",
       "  }\n",
       "\n",
       "  Animation.prototype.get_loop_state = function(){\n",
       "    var button_group = document[this.loop_select_id].state;\n",
       "    for (var i = 0; i < button_group.length; i++) {\n",
       "        var button = button_group[i];\n",
       "        if (button.checked) {\n",
       "            return button.value;\n",
       "        }\n",
       "    }\n",
       "    return undefined;\n",
       "  }\n",
       "\n",
       "  Animation.prototype.set_frame = function(frame){\n",
       "    this.current_frame = frame;\n",
       "    document.getElementById(this.img_id).src = this.frames[this.current_frame].src;\n",
       "    document.getElementById(this.slider_id).value = this.current_frame;\n",
       "  }\n",
       "\n",
       "  Animation.prototype.next_frame = function()\n",
       "  {\n",
       "    this.set_frame(Math.min(this.frames.length - 1, this.current_frame + 1));\n",
       "  }\n",
       "\n",
       "  Animation.prototype.previous_frame = function()\n",
       "  {\n",
       "    this.set_frame(Math.max(0, this.current_frame - 1));\n",
       "  }\n",
       "\n",
       "  Animation.prototype.first_frame = function()\n",
       "  {\n",
       "    this.set_frame(0);\n",
       "  }\n",
       "\n",
       "  Animation.prototype.last_frame = function()\n",
       "  {\n",
       "    this.set_frame(this.frames.length - 1);\n",
       "  }\n",
       "\n",
       "  Animation.prototype.slower = function()\n",
       "  {\n",
       "    this.interval /= 0.7;\n",
       "    if(this.direction > 0){this.play_animation();}\n",
       "    else if(this.direction < 0){this.reverse_animation();}\n",
       "  }\n",
       "\n",
       "  Animation.prototype.faster = function()\n",
       "  {\n",
       "    this.interval *= 0.7;\n",
       "    if(this.direction > 0){this.play_animation();}\n",
       "    else if(this.direction < 0){this.reverse_animation();}\n",
       "  }\n",
       "\n",
       "  Animation.prototype.anim_step_forward = function()\n",
       "  {\n",
       "    this.current_frame += 1;\n",
       "    if(this.current_frame < this.frames.length){\n",
       "      this.set_frame(this.current_frame);\n",
       "    }else{\n",
       "      var loop_state = this.get_loop_state();\n",
       "      if(loop_state == \"loop\"){\n",
       "        this.first_frame();\n",
       "      }else if(loop_state == \"reflect\"){\n",
       "        this.last_frame();\n",
       "        this.reverse_animation();\n",
       "      }else{\n",
       "        this.pause_animation();\n",
       "        this.last_frame();\n",
       "      }\n",
       "    }\n",
       "  }\n",
       "\n",
       "  Animation.prototype.anim_step_reverse = function()\n",
       "  {\n",
       "    this.current_frame -= 1;\n",
       "    if(this.current_frame >= 0){\n",
       "      this.set_frame(this.current_frame);\n",
       "    }else{\n",
       "      var loop_state = this.get_loop_state();\n",
       "      if(loop_state == \"loop\"){\n",
       "        this.last_frame();\n",
       "      }else if(loop_state == \"reflect\"){\n",
       "        this.first_frame();\n",
       "        this.play_animation();\n",
       "      }else{\n",
       "        this.pause_animation();\n",
       "        this.first_frame();\n",
       "      }\n",
       "    }\n",
       "  }\n",
       "\n",
       "  Animation.prototype.pause_animation = function()\n",
       "  {\n",
       "    this.direction = 0;\n",
       "    if (this.timer){\n",
       "      clearInterval(this.timer);\n",
       "      this.timer = null;\n",
       "    }\n",
       "  }\n",
       "\n",
       "  Animation.prototype.play_animation = function()\n",
       "  {\n",
       "    this.pause_animation();\n",
       "    this.direction = 1;\n",
       "    var t = this;\n",
       "    if (!this.timer) this.timer = setInterval(function(){t.anim_step_forward();}, this.interval);\n",
       "  }\n",
       "\n",
       "  Animation.prototype.reverse_animation = function()\n",
       "  {\n",
       "    this.pause_animation();\n",
       "    this.direction = -1;\n",
       "    var t = this;\n",
       "    if (!this.timer) this.timer = setInterval(function(){t.anim_step_reverse();}, this.interval);\n",
       "  }\n",
       "</script>\n",
       "\n",
       "<div class=\"animation\" align=\"center\">\n",
       "    <img id=\"_anim_imgKELJNGMCSWKBFHDO\">\n",
       "    <br>\n",
       "    <input id=\"_anim_sliderKELJNGMCSWKBFHDO\" type=\"range\" style=\"width:350px\" name=\"points\" min=\"0\" max=\"1\" step=\"1\" value=\"0\" onchange=\"animKELJNGMCSWKBFHDO.set_frame(parseInt(this.value));\"></input>\n",
       "    <br>\n",
       "    <button onclick=\"animKELJNGMCSWKBFHDO.slower()\">&#8211;</button>\n",
       "    <button onclick=\"animKELJNGMCSWKBFHDO.first_frame()\"><img class=\"anim_icon\" src=\"\"></button>\n",
       "    <button onclick=\"animKELJNGMCSWKBFHDO.previous_frame()\"><img class=\"anim_icon\" src=\"\"></button>\n",
       "    <button onclick=\"animKELJNGMCSWKBFHDO.reverse_animation()\"><img class=\"anim_icon\" src=\"\"></button>\n",
       "    <button onclick=\"animKELJNGMCSWKBFHDO.pause_animation()\"><img class=\"anim_icon\" src=\"\"></button>\n",
       "    <button onclick=\"animKELJNGMCSWKBFHDO.play_animation()\"><img class=\"anim_icon\" src=\"\"></button>\n",
       "    <button onclick=\"animKELJNGMCSWKBFHDO.next_frame()\"><img class=\"anim_icon\" src=\"\"></button>\n",
       "    <button onclick=\"animKELJNGMCSWKBFHDO.last_frame()\"><img class=\"anim_icon\" src=\"\"></button>\n",
       "    <button onclick=\"animKELJNGMCSWKBFHDO.faster()\">+</button>\n",
       "  <form action=\"#n\" name=\"_anim_loop_selectKELJNGMCSWKBFHDO\" class=\"anim_control\">\n",
       "    <input type=\"radio\" name=\"state\" value=\"once\" > Once </input>\n",
       "    <input type=\"radio\" name=\"state\" value=\"loop\" checked> Loop </input>\n",
       "    <input type=\"radio\" name=\"state\" value=\"reflect\" > Reflect </input>\n",
       "  </form>\n",
       "</div>\n",
       "\n",
       "\n",
       "<script language=\"javascript\">\n",
       "  /* Instantiate the Animation class. */\n",
       "  /* The IDs given should match those used in the template above. */\n",
       "  (function() {\n",
       "    var img_id = \"_anim_imgKELJNGMCSWKBFHDO\";\n",
       "    var slider_id = \"_anim_sliderKELJNGMCSWKBFHDO\";\n",
       "    var loop_select_id = \"_anim_loop_selectKELJNGMCSWKBFHDO\";\n",
       "    var frames = new Array(0);\n",
       "    \n",
       "  frames[0] = \"\"\n",
       "  frames[1] = \"\"\n",
       "  frames[2] = \"\"\n",
       "  frames[3] = \"\"\n",
       "  frames[4] = \"\"\n",
       "  frames[5] = \"\"\n",
       "  frames[6] = \"\"\n",
       "  frames[7] = \"\"\n",
       "  frames[8] = \"\"\n",
       "  frames[9] = \"\"\n",
       "  frames[10] = \"\"\n",
       "  frames[11] = \"\"\n",
       "  frames[12] = \"\"\n",
       "  frames[13] = \"\"\n",
       "  frames[14] = \"\"\n",
       "  frames[15] = \"\"\n",
       "  frames[16] = \"\"\n",
       "  frames[17] = \"\"\n",
       "  frames[18] = \"\"\n",
       "  frames[19] = \"\"\n",
       "  frames[20] = \"\"\n",
       "  frames[21] = \"\"\n",
       "  frames[22] = \"\"\n",
       "  frames[23] = \"\"\n",
       "  frames[24] = \"\"\n",
       "  frames[25] = \"\"\n",
       "  frames[26] = \"\"\n",
       "  frames[27] = \"\"\n",
       "  frames[28] = \"\"\n",
       "  frames[29] = \"\"\n",
       "  frames[30] = \"\"\n",
       "  frames[31] = \"\"\n",
       "  frames[32] = \"\"\n",
       "  frames[33] = \"\"\n",
       "  frames[34] = \"\"\n",
       "  frames[35] = \"\"\n",
       "  frames[36] = \"\"\n",
       "  frames[37] = \"\"\n",
       "  frames[38] = \"\"\n",
       "  frames[39] = \"\"\n",
       "  frames[40] = \"\"\n",
       "  frames[41] = \"\"\n",
       "  frames[42] = \"\"\n",
       "  frames[43] = \"\"\n",
       "  frames[44] = \"\"\n",
       "  frames[45] = \"\"\n",
       "  frames[46] = \"\"\n",
       "  frames[47] = \"\"\n",
       "  frames[48] = \"\"\n",
       "  frames[49] = \"\"\n",
       "  frames[50] = \"\"\n",
       "  frames[51] = \"\"\n",
       "  frames[52] = \"\"\n",
       "  frames[53] = \"\"\n",
       "  frames[54] = \"\"\n",
       "  frames[55] = \"\"\n",
       "  frames[56] = \"\"\n",
       "  frames[57] = \"\"\n",
       "  frames[58] = \"\"\n",
       "  frames[59] = \"\"\n",
       "  frames[60] = \"\"\n",
       "  frames[61] = \"\"\n",
       "  frames[62] = \"\"\n",
       "  frames[63] = \"\"\n",
       "  frames[64] = \"\"\n",
       "  frames[65] = \"\"\n",
       "  frames[66] = \"\"\n",
       "  frames[67] = \"\"\n",
       "  frames[68] = \"\"\n",
       "  frames[69] = \"\"\n",
       "  frames[70] = \"\"\n",
       "  frames[71] = \"\"\n",
       "  frames[72] = \"\"\n",
       "  frames[73] = \"\"\n",
       "  frames[74] = \"\"\n",
       "  frames[75] = \"\"\n",
       "  frames[76] = \"\"\n",
       "  frames[77] = \"\"\n",
       "  frames[78] = \"\"\n",
       "  frames[79] = \"\"\n",
       "  frames[80] = \"\"\n",
       "  frames[81] = \"\"\n",
       "  frames[82] = \"\"\n",
       "  frames[83] = \"\"\n",
       "  frames[84] = \"\"\n",
       "  frames[85] = \"\"\n",
       "  frames[86] = \"\"\n",
       "  frames[87] = \"\"\n",
       "  frames[88] = \"\"\n",
       "  frames[89] = \"\"\n",
       "  frames[90] = \"\"\n",
       "  frames[91] = \"\"\n",
       "  frames[92] = \"\"\n",
       "  frames[93] = \"\"\n",
       "  frames[94] = \"\"\n",
       "  frames[95] = \"\"\n",
       "  frames[96] = \"\"\n",
       "  frames[97] = \"\"\n",
       "  frames[98] = \"\"\n",
       "  frames[99] = \"\"\n",
       "  frames[100] = \"\"\n",
       "  frames[101] = \"\"\n",
       "  frames[102] = \"\"\n",
       "  frames[103] = \"\"\n",
       "  frames[104] = \"\"\n",
       "  frames[105] = \"\"\n",
       "  frames[106] = \"\"\n",
       "  frames[107] = \"\"\n",
       "  frames[108] = \"\"\n",
       "  frames[109] = \"\"\n",
       "  frames[110] = \"\"\n",
       "  frames[111] = \"\"\n",
       "  frames[112] = \"\"\n",
       "  frames[113] = \"\"\n",
       "  frames[114] = \"\"\n",
       "  frames[115] = \"\"\n",
       "  frames[116] = \"\"\n",
       "  frames[117] = \"\"\n",
       "  frames[118] = \"\"\n",
       "  frames[119] = \"\"\n",
       "  frames[120] = \"\"\n",
       "  frames[121] = \"\"\n",
       "  frames[122] = \"\"\n",
       "  frames[123] = \"\"\n",
       "  frames[124] = \"\"\n",
       "  frames[125] = \"\"\n",
       "  frames[126] = \"\"\n",
       "  frames[127] = \"\"\n",
       "  frames[128] = \"\"\n",
       "  frames[129] = \"\"\n",
       "  frames[130] = \"\"\n",
       "  frames[131] = \"\"\n",
       "  frames[132] = \"\"\n",
       "  frames[133] = \"\"\n",
       "  frames[134] = \"\"\n",
       "  frames[135] = \"\"\n",
       "  frames[136] = \"\"\n",
       "  frames[137] = \"\"\n",
       "  frames[138] = \"\"\n",
       "  frames[139] = \"\"\n",
       "  frames[140] = \"\"\n",
       "  frames[141] = \"\"\n",
       "  frames[142] = \"\"\n",
       "  frames[143] = \"\"\n",
       "  frames[144] = \"\"\n",
       "  frames[145] = \"\"\n",
       "  frames[146] = \"\"\n",
       "  frames[147] = \"\"\n",
       "  frames[148] = \"\"\n",
       "  frames[149] = \"\"\n",
       "  frames[150] = \"\"\n",
       "  frames[151] = \"\"\n",
       "  frames[152] = \"\"\n",
       "  frames[153] = \"\"\n",
       "  frames[154] = \"\"\n",
       "  frames[155] = \"\"\n",
       "  frames[156] = \"\"\n",
       "  frames[157] = \"\"\n",
       "  frames[158] = \"\"\n",
       "  frames[159] = \"\"\n",
       "  frames[160] = \"\"\n",
       "  frames[161] = \"\"\n",
       "  frames[162] = \"\"\n",
       "  frames[163] = \"\"\n",
       "  frames[164] = \"\"\n",
       "  frames[165] = \"\"\n",
       "  frames[166] = \"\"\n",
       "  frames[167] = \"\"\n",
       "  frames[168] = \"\"\n",
       "  frames[169] = \"\"\n",
       "  frames[170] = \"\"\n",
       "  frames[171] = \"\"\n",
       "  frames[172] = \"\"\n",
       "  frames[173] = \"\"\n",
       "  frames[174] = \"\"\n",
       "  frames[175] = \"\"\n",
       "  frames[176] = \"\"\n",
       "  frames[177] = \"\"\n",
       "  frames[178] = \"\"\n",
       "  frames[179] = \"\"\n",
       "  frames[180] = \"\"\n",
       "  frames[181] = \"\"\n",
       "  frames[182] = \"\"\n",
       "  frames[183] = \"\"\n",
       "  frames[184] = \"\"\n",
       "  frames[185] = \"\"\n",
       "  frames[186] = \"\"\n",
       "  frames[187] = \"\"\n",
       "  frames[188] = \"\"\n",
       "  frames[189] = \"\"\n",
       "  frames[190] = \"\"\n",
       "  frames[191] = \"\"\n",
       "  frames[192] = \"\"\n",
       "  frames[193] = \"\"\n",
       "  frames[194] = \"\"\n",
       "  frames[195] = \"\"\n",
       "  frames[196] = \"\"\n",
       "  frames[197] = \"\"\n",
       "  frames[198] = \"\"\n",
       "  frames[199] = \"\"\n",
       "\n",
       "\n",
       "    /* set a timeout to make sure all the above elements are created before\n",
       "       the object is initialized. */\n",
       "    setTimeout(function() {\n",
       "        animKELJNGMCSWKBFHDO = new Animation(frames, img_id, slider_id, 50, loop_select_id);\n",
       "    }, 0);\n",
       "  })()\n",
       "</script>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Imports specifically so we can render outputs in Colab.\n",
    "from matplotlib import animation\n",
    "from JSAnimation.IPython_display import display_animation\n",
    "from IPython.display import display\n",
    "\n",
    "\n",
    "def display_frames_as_gif(frames):\n",
    "    \"\"\"Displays a list of frames as a gif, with controls.\"\"\"\n",
    "    patch = plt.imshow(frames[0])\n",
    "    plt.axis('off')\n",
    "\n",
    "    def animate(i):\n",
    "        patch.set_data(frames[i])\n",
    "\n",
    "    anim = animation.FuncAnimation(\n",
    "        plt.gcf(), animate, frames = len(frames), interval=50\n",
    "    )\n",
    "    display(display_animation(anim, default_mode='loop'))\n",
    "    \n",
    "        \n",
    "# display \n",
    "display_frames_as_gif(frames)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
